import time,sys
from jili.core.printlog import print
from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
from xtquant.xttype import StockAccount
from xtquant import xtconstant
import datetime
from jili.ibot import notic_qywx
from jili.price import price_xtq as pricetool

code2order_status={
xtconstant.ORDER_UNREPORTED:"submitting",
xtconstant.ORDER_WAIT_REPORTING:"submitting",
xtconstant.ORDER_REPORTED:"working",
xtconstant.ORDER_REPORTED_CANCEL:"working",
xtconstant.ORDER_PARTSUCC_CANCEL:"working",
xtconstant.ORDER_PART_CANCEL:"working",
xtconstant.ORDER_CANCELED:"canceled",
xtconstant.ORDER_PART_SUCC:"parttraded",
xtconstant.ORDER_SUCCEEDED:"alltraded",
xtconstant.ORDER_JUNK:"rejected",
xtconstant.ORDER_UNKNOWN:"submitting"
}
code2name_order_status={
xtconstant.ORDER_UNREPORTED:"未报",
xtconstant.ORDER_WAIT_REPORTING:"待报",
xtconstant.ORDER_REPORTED:"已报",
xtconstant.ORDER_REPORTED_CANCEL:"已报待撤",
xtconstant.ORDER_PARTSUCC_CANCEL:"部成待撤",
xtconstant.ORDER_PART_CANCEL:"部撤",
xtconstant.ORDER_CANCELED:"已撤",
xtconstant.ORDER_PART_SUCC:"部成",
xtconstant.ORDER_SUCCEEDED:"已成",
xtconstant.ORDER_JUNK:"废单",
xtconstant.ORDER_UNKNOWN:"未知"
}
code2name_order_type={
xtconstant.STOCK_BUY:"买入",
xtconstant.STOCK_SELL:"卖出",
xtconstant.CREDIT_FIN_BUY:"融资买入",
xtconstant.CREDIT_SLO_SELL:"融券卖出",
xtconstant.CREDIT_BUY_SECU_REPAY:"买券还券",
xtconstant.CREDIT_DIRECT_SECU_REPAY:"直接还券",
xtconstant.CREDIT_SELL_SECU_REPAY:"卖券还款",
xtconstant.CREDIT_DIRECT_CASH_REPAY:"直接还款"

}
code2name_price_type={
xtconstant.LATEST_PRICE:"最新价",
xtconstant.FIX_PRICE:"指定价",
xtconstant.MARKET_SH_CONVERT_5_CANCEL:"上交所最优五档即时成交剩余撤销",
xtconstant.MARKET_SH_CONVERT_5_LIMIT:"上交所最优五档即时成交剩转限价",
xtconstant.MARKET_PEER_PRICE_FIRST:"上交所对手方最优价格委托",
xtconstant.MARKET_MINE_PRICE_FIRST:"上交所本方最优价格委托",
xtconstant.MARKET_PEER_PRICE_FIRST:"深交所对手方最优价格委托",
xtconstant.MARKET_MINE_PRICE_FIRST:"深交所本方最优价格委托",
xtconstant.MARKET_SZ_INSTBUSI_RESTCANCEL:"深交所即时成交剩余撤销委托",
xtconstant.MARKET_SZ_CONVERT_5_CANCEL:"深交所最优五档即时成交剩余撤销",
xtconstant.MARKET_SZ_FULL_OR_CANCEL:"深交所全额成交或撤销委托"
}
def xt2dict(c):
    cc={}
    for i in dir(c):
        if i.startswith("_"):
            continue
        cc[i]=getattr(c,i)
    return cc


def ats2xt_price_type(pricetype):
    if pricetype == "market":
        return xtconstant.LATEST_PRICE
    else:
        return xtconstant.FIX_PRICE
def xt2ats_price_type(pricetype):
    if pricetype == xtconstant.FIX_PRICE:
        return "limit"
    else:
        return "market"

def ats2xt_order_type(account_type,openclose, bs):
    """
    融资买入 - xtconstant.CREDIT_FIN_BUY
    融券卖出 - xtconstant.CREDIT_SLO_SELL
    买券还券 - xtconstant.CREDIT_BUY_SECU_REPAY
    直接还券 - xtconstant.CREDIT_DIRECT_SECU_REPAY
    卖券还款 - xtconstant.CREDIT_SELL_SECU_REPAY
    直接还款 - xtconstant.CREDIT_DIRECT_CASH_REPAY
    """
    order_type = None
    if account_type == xtconstant.SECURITY_ACCOUNT:#股票
        if openclose == "primary":
            if bs == "buy":
                order_type = xtconstant.ETF_PURCHASE#ETF申购
            elif bs == "sell":
                order_type = xtconstant.ETF_REDEMPTION#ETF赎回
        else:
            if bs == "buy":
                order_type = xtconstant.STOCK_BUY#买入
            elif bs == "sell":
                order_type = xtconstant.STOCK_SELL#卖出
    elif account_type == xtconstant.CREDIT_ACCOUNT:#信用
        if openclose == "open":
            if bs == "buy":
                order_type = xtconstant.STOCK_BUY#担保品买入
            elif bs == "sell":
                order_type = xtconstant.CREDIT_SLO_SELL#融券卖出
        elif openclose == "close":
            if bs == "sell":
                order_type = xtconstant.STOCK_SELL#担保品卖出
            elif bs == "buy":
                order_type = xtconstant.CREDIT_BUY_SECU_REPAY#买券还券
        elif openclose =="credit":
            if bs == "buy":
                order_type = xtconstant.CREDIT_FIN_BUY#融资买入
            elif bs == "sell":
                order_type = xtconstant.CREDIT_SELL_SECU_REPAY#卖券还款
        elif openclose == "debt":
            if bs == "buy":
                order_type = xtconstant.CREDIT_DIRECT_CASH_REPAY#直接还款
            elif bs == "sell":
                order_type = xtconstant.CREDIT_DIRECT_SECU_REPAY#直接还券
    elif account_type == xtconstant.FUTURE_ACCOUNT or account_type == xtconstant.FUTURE_OPTION_ACCOUNT:
        if openclose=="open":
            if bs == "buy":
                order_type = xtconstant.FUTURE_OPEN_LONG#开多
            elif bs == "sell":
                order_type = xtconstant.FUTURE_OPEN_SHORT#开空
        elif openclose=="close":
            if bs == "buy":
                order_type = xtconstant.FUTURE_CLOSE_LONG_HISTORY_FIRST#平多,历史优先
            elif bs == "sell":
                order_type = xtconstant.FUTURE_CLOSE_SHORT_HISTORY_FIRST#平空,历史优先
        elif openclose=="close_yesterday":
            if bs == "buy":
                order_type = xtconstant.FUTURE_CLOSE_LONG_HISTORY#平多昨
            elif bs == "sell":
                order_type = xtconstant.FUTURE_CLOSE_SHORT_HISTORY#平空昨
        elif openclose=="close_today":
            if bs == "buy":
                order_type = xtconstant.FUTURE_CLOSE_LONG_TODAY#平多今
            elif bs == "sell":
                order_type = xtconstant.FUTURE_CLOSE_SHORT_TODAY#平空今
        elif openclose == "deal_option":
            order_type = xtconstant.OPTION_FUTURE_OPTION_EXERCISE#期货期权行权
    elif account_type == xtconstant.STOCK_OPTION_ACCOUNT:#股票期权
        if openclose=="open":
            if bs == "buy":
                order_type = xtconstant.STOCK_OPTION_BUY_OPEN#买入开仓
            elif bs == "sell":
                order_type = xtconstant.STOCK_OPTION_SELL_OPEN#卖出开仓
        elif openclose=="close":
            if bs == "buy":
                order_type = xtconstant.STOCK_OPTION_BUY_CLOSE#买入平仓
            elif bs == "sell":
                order_type = xtconstant.STOCK_OPTION_SELL_CLOSE#卖出平仓
        elif openclose=="hold":
            if bs == "buy":
                order_type = xtconstant.STOCK_OPTION_COVERED_OPEN#备兑开仓
            elif bs == "sell":
                order_type = xtconstant.STOCK_OPTION_COVERED_CLOSE#备兑平仓
        elif openclose == "deal_option":
            if bs == "buy":
                order_type = xtconstant.STOCK_OPTION_CALL_EXERCISE#认购行权
            elif bs == "sell":
                order_type = xtconstant.STOCK_OPTION_PUT_EXERCISE#认沽行权
            elif openclose == "lock":
                order_type = xtconstant.STOCK_OPTION_SECU_LOCK#证券锁定
            elif openclose == "unlock":
                order_type = xtconstant.STOCK_OPTION_SECU_UNLOCK#证券解锁
    if order_type is None:
        info = "不认识的指令" + str(account_type)+"," +openclose+","+bs
        print("sys", info)
        return None
    return order_type

xt2ats_bs={
xtconstant.DIRECTION_FLAG_LONG:"buy",
xtconstant.DIRECTION_FLAG_SHORT:"sell",
}
xt2ats_openclose={
xtconstant.OFFSET_FLAG_OPEN:"open",
xtconstant.OFFSET_FLAG_CLOSE:"close",
xtconstant.OFFSET_FLAG_FORCECLOSE:"close_force",
xtconstant.OFFSET_FLAG_CLOSETODAY:"close_today",
xtconstant.OFFSET_FLAG_ClOSEYESTERDAY:"close_yesterday",
}
def xt2openclose(account_type,order_type, price_type,direction,offset_flag):
    info = ""
    openclose=None
    bs=None
    if account_type==xtconstant.SECURITY_ACCOUNT:
        if order_type == xtconstant.STOCK_BUY:
            openclose, bs = "open", "buy"
        elif order_type == xtconstant.STOCK_SELL:
            openclose, bs = "close", "sell"
        elif order_type == xtconstant.ETF_PURCHASE:
            openclose, bs = "primary", "buy"
        elif order_type == xtconstant.ETF_REDEMPTION:
            openclose, bs = "primary", "sell"
    elif account_type==xtconstant.CREDIT_ACCOUNT:
        if order_type in [xtconstant.STOCK_BUY, xtconstant.CREDIT_BUY]:
            openclose, bs = "open", "buy"
        elif order_type in [xtconstant.STOCK_SELL, xtconstant.CREDIT_SELL]:
            openclose, bs = "close", "sell"
        elif order_type == xtconstant.CREDIT_FIN_BUY:
            openclose, bs = "credit", "buy"
        elif order_type == xtconstant.CREDIT_SLO_SELL:
            openclose, bs = "open", "sell"
        elif order_type == xtconstant.CREDIT_BUY_SECU_REPAY:
            openclose, bs = "close", "buy"
        elif order_type == xtconstant.CREDIT_SELL_SECU_REPAY:
            openclose, bs = "credit", "sell"
        elif order_type == xtconstant.CREDIT_DIRECT_CASH_REPAY:
            openclose, bs = "debt", "buy"
        elif order_type == xtconstant.CREDIT_DIRECT_SECU_REPAY:
            openclose, bs = "debt", "sell"
    elif account_type==xtconstant.FUTURE_ACCOUNT:
        bs=xt2ats_bs.get(direction)
        openclose=xt2ats_openclose.get(offset_flag,"close")
    elif account_type==xtconstant.STOCK_OPTION_ACCOUNT or account_type==xtconstant.FUTURE_OPTION_ACCOUNT:
        bs = xt2ats_bs.get(direction)
        openclose = xt2ats_openclose.get(offset_flag, "close")
    if openclose is None:
        info = "不认识的指令" + str(account_type)+str(order_type)+str(price_type)+str(direction)+str(offset_flag)
        print("sys", "不认识的指令", account_type,order_type, price_type,direction,offset_flag)
    info = info + code2name_order_type[order_type] + "," + str(account_type)+str(order_type)+str(price_type)+str(direction)+str(offset_flag)  # xtdict.code2name_oprice_type[price_type]
    """
    股票

    买入 - xtconstant.STOCK_BUY
    卖出 - xtconstant.STOCK_SELL
    信用

    担保品买入 - xtconstant.CREDIT_BUY
    担保品卖出 - xtconstant.CREDIT_SELL
    融资买入 - xtconstant.CREDIT_FIN_BUY
    融券卖出 - xtconstant.CREDIT_SLO_SELL
    买券还券 - xtconstant.CREDIT_BUY_SECU_REPAY
    直接还券 - xtconstant.CREDIT_DIRECT_SECU_REPAY
    卖券还款 - xtconstant.CREDIT_SELL_SECU_REPAY
    直接还款 - xtconstant.CREDIT_DIRECT_CASH_REPAY
    专项融资买入 - xtconstant.CREDIT_FIN_BUY_SPECIAL
    专项融券卖出 - xtconstant.CREDIT_SLO_SELL_SPECIAL
    专项买券还券 - xtconstant.CREDIT_BUY_SECU_REPAY_SPECIAL
    专项直接还券 - xtconstant.CREDIT_DIRECT_SECU_REPAY_SPECIAL
    专项卖券还款 - xtconstant.CREDIT_SELL_SECU_REPAY_SPECIAL
    专项直接还款 - xtconstant.CREDIT_DIRECT_CASH_REPAY_SPECIAL
    期货六键风格

    开多 - xtconstant.FUTURE_OPEN_LONG
    平昨多 - xtconstant.FUTURE_CLOSE_LONG_HISTORY
    平今多 - xtconstant.FUTURE_CLOSE_LONG_TODAY
    开空 - xtconstant.FUTURE_OPEN_SHORT
    平昨空 - xtconstant.FUTURE_CLOSE_SHORT_HISTORY
    平今空 - xtconstant.FUTURE_CLOSE_SHORT_TODAY
    期货四键风格

    平多，优先平今 - xtconstant.FUTURE_CLOSE_LONG_TODAY_FIRST
    平多，优先平昨 - xtconstant.FUTURE_CLOSE_LONG_HISTORY_FIRST
    平空，优先平今 - xtconstant.FUTURE_CLOSE_SHORT_TODAY_FIRST
    平空，优先平昨 - xtconstant.FUTURE_CLOSE_SHORT_HISTORY_FIRST
    期货两键风格

    卖出，如有多仓，优先平仓，优先平今，如有余量，再开空 - xtconstant.FUTURE_CLOSE_LONG_TODAY_HISTORY_THEN_OPEN_SHORT
    卖出，如有多仓，优先平仓，优先平昨，如有余量，再开空 - xtconstant.FUTURE_CLOSE_LONG_HISTORY_TODAY_THEN_OPEN_SHORT
    买入，如有空仓，优先平仓，优先平今，如有余量，再开多 - xtconstant.FUTURE_CLOSE_SHORT_TODAY_HISTORY_THEN_OPEN_LONG
    买入，如有空仓，优先平仓，优先平昨，如有余量，再开多 - xtconstant.FUTURE_CLOSE_SHORT_HISTORY_TODAY_THEN_OPEN_LONG
    买入，不优先平仓 - xtconstant.FUTURE_OPEN
    卖出，不优先平仓 - xtconstant.FUTURE_CLOSE
    期货 - 跨商品套利

    开仓 - xtconstant.FUTURE_ARBITRAGE_OPEN
    平, 优先平昨 - xtconstant.FUTURE_ARBITRAGE_CLOSE_HISTORY_FIRST
    平, 优先平今 - xtconstant.FUTURE_ARBITRAGE_CLOSE_TODAY_FIRST
    期货展期

    看多, 优先平昨 - xtconstant.FUTURE_RENEW_LONG_CLOSE_HISTORY_FIRST
    看多，优先平今 - xtconstant.FUTURE_RENEW_LONG_CLOSE_TODAY_FIRST
    看空，优先平昨 - xtconstant.FUTURE_RENEW_SHORT_CLOSE_HISTORY_FIRST
    看空，优先平今 - xtconstant.FUTURE_RENEW_SHORT_CLOSE_TODAY_FIRST
    股票期权

    买入开仓，以下用于个股期权交易业务 - xtconstant.STOCK_OPTION_BUY_OPEN
    卖出平仓 - xtconstant.STOCK_OPTION_SELL_CLOSE
    卖出开仓 - xtconstant.STOCK_OPTION_SELL_OPEN
    买入平仓 - xtconstant.STOCK_OPTION_BUY_CLOSE
    备兑开仓 - xtconstant.STOCK_OPTION_COVERED_OPEN
    备兑平仓 - xtconstant.STOCK_OPTION_COVERED_CLOSE
    认购行权 - xtconstant.STOCK_OPTION_CALL_EXERCISE
    认沽行权 - xtconstant.STOCK_OPTION_PUT_EXERCISE
    证券锁定 - xtconstant.STOCK_OPTION_SECU_LOCK
    证券解锁 - xtconstant.STOCK_OPTION_SECU_UNLOCK
    期货期权

    期货期权行权 - xtconstant.OPTION_FUTURE_OPTION_EXERCISE
    ETF申赎

    申购 - xtconstant.ETF_PURCHASE
    赎回 - xtconstant.ETF_REDEMPTION
    """
    return openclose, bs, info
xt2ats_posbs={
xtconstant.DIRECTION_FLAG_LONG:"buy",
xtconstant.DIRECTION_FLAG_SHORT:"sell",
}

class onTraderTool(XtQuantTraderCallback):
    def __init__(self,tradertool,account,ss,ssconfig):
        self.tradertool=tradertool
        self.orders_watchdog={}
        self.account=account
        self.orders_watchdog_closeall = {}
        self.ss=ss
        self.working_orders={}
        self.isibot=False
        self.qywx_bot_key=""
        self.open_objs=[]
        self.reset_order_checktick={}
        self.pricetool0=pricetool.pricetool()
        if "strategy_name" in ssconfig.keys():
            self.ssname = ssconfig["strategy_name"]
        else:
            self.ssname = ""
        self.strategy_name0=ssconfig.get("strategy_name0","")
        if "qywx_bot_key" in ssconfig.keys():
            self.isibot=True
            self.qywx_bot_key=ssconfig["qywx_bot_key"]
        self.order_end_stat=[xtconstant.ORDER_PART_CANCEL,xtconstant.ORDER_CANCELED,xtconstant.ORDER_PART_SUCC,xtconstant.ORDER_SUCCEEDED,xtconstant.ORDER_JUNK]
    def settradetool(self,tradertool):
        self.tradertool = tradertool
    def deal_reset_order(self,obj, orderid, o):
        if "resetprice" in o.keys():
            price=o["resetprice"]
            if obj not in self.reset_order_checktick.keys():
                self.reset_order_checktick[obj] = {}
            self.reset_order_checktick[obj][orderid]=price
    def deal_close_all(self,obj,signal,t,pos):
        isdeal=True
        if obj in self.working_orders.keys():
            t=self.working_orders[obj]
            if t:
                # 撤单，撤单成功后委托
                for orderid,o in t.items():
                    self.tradertool.cancel_order_stock(self.account, o.order_id)
                self.orders_watchdog_closeall[obj] = [signal,t,pos]
                isdeal=False
        if isdeal:
            if pos.can_use_volume>0:
                orderid = self.tradertool.order_stock(self.account, obj, xtconstant.STOCK_SELL, pos.can_use_volume,
                                                  xtconstant.FIX_PRICE,
                                                  t["lastPrice"], self.ssname, signal["k"]+signal["msg"])
                now = datetime.datetime.now()
                self.set_watchdog_order(obj, now, orderid)
                print("deal_close_all", self.orders_watchdog)
            else:
                print("deal_close_all", obj, "持仓为0")
    def set_watchdog_order(self,obj,timekey,orderid):
        if obj not in self.orders_watchdog.keys():
            self.orders_watchdog[obj]={}
        self.orders_watchdog[obj][orderid]=[timekey,None,None]
    def ontick(self,obj,timekey,t):
        if obj in self.reset_order_checktick.keys():
            oo=self.reset_order_checktick[obj]
            if oo:
                p=t["lastPrice"]
                deals=[]
                for orderid,price in oo.items():
                    if p<=price:
                        now = datetime.datetime.now()-datetime.timedelta(hours=1)
                        self.set_watchdog_order(obj, now, orderid)
                        deals.append(orderid)
                if deals:
                    for i in deals:
                        del oo[i]
            if not oo:
                del self.reset_order_checktick[obj]
        if obj in self.orders_watchdog.keys():
            o=self.orders_watchdog[obj]
            for orderid,oo in o.items():
                oo[2]=t
                delt=timekey-oo[0]
                delt=delt.total_seconds()
                if delt>=15:
                    self.tradertool.cancel_order_stock(self.account, orderid)
    def deal_ibot_order(self,r):
        # print("ibot",self.qywx_bot_key,self.isibot,r.stock_code,r.traded_volume,r.strategy_name,r.order_type,r.order_status)
        try:
            if self.isibot:
                obj=r.stock_code
                name=obj
                info=self.pricetool0.get_objinfo(obj)
                if info:
                    if "InstrumentName" in info.keys():
                        name=info["InstrumentName"]
                if r.strategy_name == self.ssname:
                    s=""
                    if r.order_status == xtconstant.ORDER_SUCCEEDED:  # xtconstant.ORDER_PART_CANCEL
                        s = self.strategy_name0+":"+name + ':全部成交 '
                    elif r.order_status == xtconstant.ORDER_PART_CANCEL:
                        s = self.strategy_name0+":"+name + ':部成部撤 '
                    elif r.order_status == xtconstant.ORDER_REPORTED:
                        s = self.strategy_name0+":"+name + ':已报单 '
                    elif r.order_status == xtconstant.ORDER_CANCELED:
                        s = self.strategy_name0+":"+name + ':已撤单 '
                    elif r.order_status == xtconstant.ORDER_JUNK:
                        s = self.strategy_name0+":"+name + ':废单 '
                    else:
                        print("不是最终状态")
                    if s!="":
                        n0=code2name_order_type.get(r.order_type,r.order_type)
                        if "买" in n0:
                            s=s+'\n>**<font color="warning">'
                        elif "卖" in n0:
                            s=s+'\n>**<font color="info">'
                        else:
                            s=s+'\n>**<font color="comment">'
                        s = s+n0+'</font>**  \n>股票代码：' + obj +' \n>报单价格：' + str(
                            r.price) +' \n>报单数量：' + str(r.order_volume) +' \n>订单说明：' + str(r.order_remark)
                        print("ibot msg:", s)
                        notic_qywx.send_markdown(s, self.qywx_bot_key)
                    else:
                        print("不是最终状态")
                else:
                    print("ibot,不是本策略")
            else:
                print("ibot,没有配置机器人")
        except Exception as e:
            print("deal_ibot_order err",e)
    def on_stock_order(self, r):
        """
        委托回报推送
        :param order: XtOrder对象
        :return:
        """

        print("on_stock_order",r.stock_code,r.traded_volume,r.traded_volume)
        try:
            self.ss.on_order(r)
            #self.ss.deal_out_objs(r)
            obj=r.stock_code
            orderid=r.order_id
            stat = r.order_status
            if r.order_volume>r.traded_volume:
                if obj in self.orders_watchdog.keys():
                    if orderid in self.orders_watchdog[obj].keys():
                        self.orders_watchdog[obj][orderid][1]=r
            elif r.order_volume>r.traded_volume:
                if obj in self.orders_watchdog.keys():
                    if orderid in self.orders_watchdog[obj].keys():
                        del self.orders_watchdog[obj][orderid]
                if len(self.orders_watchdog[obj])==0:
                    del self.orders_watchdog[obj]
            if obj not in self.working_orders.keys():
                self.working_orders[obj]={}
            self.working_orders[obj][orderid]=r
            if stat in self.order_end_stat:
                del self.working_orders[obj][orderid]
            if len(self.working_orders[obj])==0:
                if obj in self.orders_watchdog_closeall.keys():
                    signal, t, pos=self.orders_watchdog_closeall[obj]
                    orderid = self.tradertool.order_stock(self.account, obj, xtconstant.STOCK_SELL, pos.can_use_volume,
                                                          xtconstant.FIX_PRICE,
                                                          t["lastPrice"], self.ssname, signal["msg"])
                    now = datetime.datetime.now()
                    self.set_watchdog_order(obj, now, orderid)
                    print("on_stock_order", self.orders_watchdog)
            if r.strategy_name==self.ssname:
                print('本策略-委托回调',"strategy_name",r.strategy_name,r.order_remark,obj,orderid,r.order_type,r.order_status,code2name_order_status[r.order_status],r.status_msg,"order_volume",r.order_volume,r.price,"traded_volume",r.traded_volume,r.price_type)
            else:
                print('外部-委托回调',"strategy_name",r.strategy_name,r.order_remark,obj,orderid,r.order_type,r.order_status,code2name_order_status[r.order_status],"order_volume",r.order_volume,"traded_volume",r.price,r.traded_volume,r.traded_volume,r.price_type)
            self.deal_ibot_order(r)
            # if r.traded_volume > 0 and r.order_status in [xtconstant.ORDER_SUCCEEDED,xtconstant.ORDER_PART_CANCEL]:
            #     if r.strategy_name==self.ssname or r.stock_code in self.ss.out_objs:
            #         self.ss.refresh_pos()
        except Exception as e:
            print("on_stock_order err",e)




    def on_stock_trade(self, r):
        """
        成交变动推送
        :param trade: XtTrade对象
        :return:
        """
        if r.strategy_name==self.ssname:
            print('本策略-成交',"strategy_name",r.strategy_name,r.order_remark,r.stock_code,r.order_id,"order_type",r.order_type,code2name_order_type[r.order_type],datetime.datetime.fromtimestamp(r.traded_time),"traded_price",r.traded_price,"traded_volume",r.traded_volume,"traded_amount",r.traded_amount)

        else:
            print('外部-成交',"strategy_name",r.strategy_name,r.order_remark,r.stock_code,r.order_id,"order_type",r.order_type,code2name_order_type[r.order_type],datetime.datetime.fromtimestamp(r.traded_time),"traded_price",r.traded_price,"traded_volume",r.traded_volume)


    def on_order_error(self, r):
        """
        委托失败推送
        :param order_error:XtOrderError 对象
        :return:
        """
        # print("on order_error callback")
        # print(order_error.order_id, order_error.error_id, order_error.error_msg)
        if r.strategy_name == self.ssname:
            print('本策略-下单错误', "strategy_name", r.strategy_name, r.order_id, r.error_id,r.error_msg)
            s = self.strategy_name0+':下单失败 \n>委托ID：' +str(r.order_id) + '  \n>错误ID：' + str(r.error_id) + '  \n>说明：' + str(r.error_msg)
            print("ibot msg:", s)
            notic_qywx.send_markdown(s, self.qywx_bot_key)

    def on_cancel_error(self, r):
        """
        撤单失败推送
        :param cancel_error: XtCancelError 对象
        :return:
        """
        if r.strategy_name == self.ssname:
            print('本策略-撤单错误', "strategy_name", r.strategy_name, r.order_id, r.error_id, r.error_msg)
            s = self.strategy_name0+':撤单失败 \n>委托ID：' +str(r.order_id) + '  \n>错误ID：' + str(r.error_id) + '  \n>说明：' + str(r.error_msg)
            print("ibot msg:", s)
            notic_qywx.send_markdown(s, self.qywx_bot_key)

    def on_order_stock_async_response(self, r):
        """
        异步下单回报推送
        :param r: XtOrderResponse 对象
        :return:
        """
        if r.strategy_name == self.ssname:
            print(f"异步委托回调 {r.order_remark}")

    def on_cancel_order_stock_async_response(self, r):
        """
        :param r: XtCancelOrderResponse 对象
        :return:
        """
        if r.strategy_name == self.ssname:
            print("异步撤单回调", sys._getframe().f_code.co_name)


    def on_account_status(self, r):
        """
        :param r: XtAccountStatus 对象
        :return:
        """
        print("账号状态",r.account_id,r.broker_type,r.platform_id,r.account_classification,r.login_status)
class tradetool():
    def __init__(self,config):
        self.fund={}
        self.pos={}
        self.orders=[]
        self.working_orders={}
        self.trades=[]

        self.connect_result=-1
        if "qmt_path" in config.keys():
            session_id = int(time.time())
            self.tradertool = XtQuantTrader(config["qmt_path"], session_id)
            # 创建资金账号为 800068 的证券账号对象
            self.account = StockAccount(config["account_id"], config["account_type"])
            self.investorid=config["account_id"]
            self.account_type=config["account_type"].lower()#stock,credit,future
            # 创建交易回调类对象，并声明接收回调
            self.ontradertool = onTraderTool(self.tradertool,self.account,self,config)
            self.tradertool.register_callback(self.ontradertool)
            # 启动交易线程
            self.tradertool.start()
            # 建立交易连接，返回0表示连接成功
            connect_result = self.tradertool.connect()
            if connect_result!=0:
                print("交易连接失败，错误代码为",connect_result)
                print("请检查后再启动策略")
                # sys.exit()
            print('建立交易连接，连接成功', connect_result)
            subscribe_result = self.tradertool.subscribe(self.account)
            print('对交易回调进行订阅，订阅后可以收到交易主推，返回0表示订阅成功', subscribe_result)
            self.connect_result=connect_result
        # return self.connect_result
    def login(self,qmt_path=None,account_id=None,account_type=None):
        if qmt_path is not None and account_id is not None and account_type is not None:
            session_id = int(time.time())
            self.tradertool = XtQuantTrader(qmt_path, session_id)
            # 创建资金账号为 800068 的证券账号对象
            self.investorid = account_id
            self.account = StockAccount(account_id, account_type)
            self.account_type = account_type.lower()
            # 创建交易回调类对象，并声明接收回调
            self.ontradertool = onTraderTool(self.tradertool, self.account, self, self.config)
            self.tradertool.register_callback(self.ontradertool)
            # 启动交易线程
            self.tradertool.start()
            # 建立交易连接，返回0表示连接成功
            connect_result = self.tradertool.connect()
            if connect_result != 0:
                print("交易连接失败，错误代码为", connect_result)
                print("请检查后再启动策略")
                # sys.exit()
            print('建立交易连接，连接成功', connect_result)
            subscribe_result = self.tradertool.subscribe(self.account)
            print('对交易回调进行订阅，订阅后可以收到交易主推，返回0表示订阅成功', subscribe_result)
            self.connect_result = connect_result
        self.qry_info()
        return self.connect_result
    def get_version(self):
        return "20250526"
    def logout(self):
        self.tradertool.stop()
        return True
    def cancel_order(self,orderid):
        self.tradertool.cancel_order_stock(self.account, orderid)
    def qry_info(self,req={}):
        self.get_fund()
        self.get_pos()
        self.get_orders()
        self.get_trade()
    def deal_order(self,c,orderid=None):
        obj, mkcode = pricetool.code2obj(c.stock_code)
        if orderid is None:
            orderid=c.order_id
        #direction,offset_flag
        pricetype = xt2ats_price_type(c.order_type)
        status = code2order_status[c.order_status]
        statusmsg = code2name_order_status[c.order_status]
        openclose, bs, orderinfo = xt2openclose(c.account_type,c.order_type, c.price_type,c.direction,c.offset_flag)
        order = {"obj": obj, "code": c.stock_code, "mkcode": mkcode, "bs": bs, "openclose": openclose,
                 "orderid": orderid, "sysid": c.order_sysid, "qty": c.order_volume, "qty1": c.traded_volume,
                 "price": c.price, "price1": c.traded_price, "status": status,
                 "statusmsg": statusmsg + ":" + str(c.order_status) + c.status_msg,
                 "ssid": c.strategy_name, "orderinfo": c.order_remark + "," + orderinfo}
        order["qty0"] = c.order_volume - c.traded_volume
        order["pricetype"]=pricetype
        order["timekey"] = datetime.datetime.fromtimestamp(c.order_time)
        for k, v in xt2dict(c).items():
            if k not in order.keys():
                order[k] = v
        return order
    def get_orders(self,isworking=False):
        """
        stock_code	str	证券代码，例如"600000.SH"
        order_id	int	订单编号
        order_sysid	str	柜台合同编号
        order_time	int	报单时间
        order_type	int	委托类型，参见数据字典
        order_volume	int	委托数量
        price_type	int	报价类型，该字段在返回时为柜台返回类型，不等价于下单传入的price_type，枚举值不一样功能一样，参见数据字典
        price	float	委托价格
        traded_volume	int	成交数量
        traded_price	float	成交均价
        order_status	int	委托状态，参见数据字典
        status_msg	str	委托状态描述，如废单原因
        strategy_name	str	策略名称
        order_remark	str	委托备注，最大 24 个英文字符
        :param isworking:
        :return:
        """
        self.working_orders = {}
        oo=[]
        os=self.tradertool.query_stock_orders(self.account, cancelable_only = isworking)

        if os:
            for c in os:
                order=self.deal_order(c)
                oo.append(order)
                if order["qty0"]>0:
                    self.working_orders[order["orderid"]]=order
                    print("working_orders", order)
                else:
                    print("orders", order)
        self.orders=oo
        return oo
    def get_pos(self):
        """
        stock_code	str	证券代码
        volume	int	持仓数量
        can_use_volume	int	可用数量
        open_price	float	开仓价
        market_value	float	市值
        frozen_volume	int	冻结数量
        on_road_volume	int	在途股份
        yesterday_volume	int	昨夜拥股
        avg_price	float	成本价
        direction	int	多空方向，股票不适用；参见数据字典

        :return:
        """
        position = self.tradertool.query_stock_positions(self.account)
        poss={}
        if position:
            for c in position:
                if c.volume!=0:
                    obj,mkcode=pricetool.code2obj(c.stock_code)
                    bs=xt2ats_posbs[c.direction]
                    pos = {"obj": obj, "code": c.stock_code,"mkcode":mkcode,"bs":bs,
                             "qty": c.volume, "qty_avl": c.can_use_volume,"qty_yesterday":c.yesterday_volume,"qty_today":c.volume-c.can_use_volume,"qty_credit":0,
                             "price": c.avg_price, "margin": c.market_value}
                    for k, v in xt2dict(c).items():
                        if k not in pos.keys():
                            pos[k] = v
                    if obj not in poss.keys():
                        poss[obj]={}
                    poss[obj][bs]=pos
                    print("pos", pos)
        if self.account_type == "credit":#CREDIT
            datas = self.tradertool.query_stk_compacts(self.account)
            if datas:
                for c in datas:
                    if c.real_compact_vol != 0:
                        if c.compact_type==48:
                            obj,mkcode=pricetool.code2obj(c.instrument_id)
                            if obj in poss.keys():
                                if "buy" in poss[obj].keys():
                                    poss[obj]["buy"]["qty_credit"]=c.real_compact_vol
                        elif c.compact_type==49:
                            obj, mkcode = pricetool.code2obj(c.instrument_id)
                            if obj in poss.keys():
                                if "buy" in poss[obj].keys():
                                    poss[obj]["buy"]["qty_credit"] = -c.real_compact_vol
        self.pos=poss
        return poss

    def get_fund(self):
        """
        cash	float	可用金额
        frozen_cash	float	冻结金额
        market_value	float	持仓市值
        total_asset	float	总资产
        :return:
        """
        if self.account_type=="stock":
            c= self.tradertool.query_stock_asset(self.account)
            fund={"cash":c.cash,"frozen0":c.frozen_cash,"margin":c.market_value,"balance":c.total_asset,"total_balance":c.total_asset}
        else:
            c= self.tradertool.query_credit_detail(self.account)
            print("query_credit_detail",len(c))
            c=c[0]
            fund={"cash":c.m_dAvailable,"frozen0":c.m_dFrozenCash,"margin":c.m_dMarketValue,"balance":c.m_dAssureAsset,"total_balance":c.m_dBalance,"credit":c.m_dTotalDebt}
        for k,v in xt2dict(c).items():
            if k not in fund.keys():
                fund[k]=v
        self.fund=fund
        print("fund",fund)
        return fund
    def get_trade(self):
        t=self.tradertool.query_stock_trades(self.account)
        trades=[]
        if t:
            for c in t:
                obj, mkcode = pricetool.code2obj(c.stock_code)
                oid=c.order_id
                tt={"obj":obj,"mkcode":mkcode,"timekey":datetime.datetime.fromtimestamp(c.traded_time),"orderid": oid, "sysid": oid}
                for k, v in xt2dict(c).items():
                    tt[k]=v
                trades.append(tt)
                print("trade", tt)
        self.trades=trades
        return trades
    def submit_order(self,order):#报单
        obj=order["obj"]
        mkcode=order.get("mkcode")
        if mkcode=="":
            mkcode=None
        bs=order["bs"]
        openclose=order["openclose"]
        price=order["price"]
        qty=order["qty"]
        pricetype=order.get("pricetype","limit")
        pricetype=ats2xt_price_type(pricetype)
        ssid=order.get("ssid","")
        msg=order.get("msg","")
        code = pricetool.obj2code(obj, mkcode)
        # order_type = ats2xt_order_type(3, openclose, bs)
        order_type=ats2xt_order_type(self.account.account_type,openclose, bs)
        #order_stock(account, stock_code, order_type, order_volume, price_type, price, strategy_name, order_remark)
        print("submit_order",order)
        print("submit_order-order_stock", "stock_code",code, "order_type",order_type, "order_volume",qty, "price_type",pricetype, "price",price, "strategy_name",ssid, "order_remark",msg,"account",self.investorid)
        if order_type is not None:
            r=self.tradertool.order_stock(self.account, stock_code=code, order_type=order_type, order_volume=qty, price_type=pricetype, price=price, strategy_name=ssid, order_remark=msg)
        else:
            r=-1
        # print("submit_order",order)
        # print("submit_order-order_stock", "stock_code",code, "order_type",order_type, "order_volume",qty, "price_type",pricetype, "price",price, "strategy_name",ssid, "order_remark",msg,"account",self.investorid)
        print("submit_order-r",r)
        # if r==-1:
        #     print("submit_order失败")
        # else:
        #     print("submit_order成功,订单编号",r)
        return r
    def openbuy(self,timekey,qty,posrate=None,amount=None,price=None,msg="",ssid="",obj=None,code=None):
        print("pos openbuy",timekey,qty,posrate,amount,price,msg,ssid,obj,code)
        order={"obj":obj,"bs":"buy","openclose":"open","price":price,"qty":qty,"pricetype":"limit","ssid":ssid,"msg":msg,"code":code}
        r=self.submit_order(order)
        if r==0:
            print("openbuy失败")
            return -1
        else:
            print("openbuy成功,订单编号",r)
            return r
    def creditbuy(self,timekey,qty,posrate=None,amount=None,price=None,msg="",ssid="",obj=None,code=None):
        print("pos creditbuy",timekey,qty,posrate,amount,price,msg,ssid,obj,code)
        order={"obj":obj,"bs":"buy","openclose":"credit","price":price,"qty":qty,"pricetype":"limit","ssid":ssid,"msg":msg,"code":code}
        r=self.submit_order(order)
        if r==0:
            print("creditbuy失败")
            return -1
        else:
            print("creditbuy成功,订单编号",r)
            return r
    def creditsell(self,timekey,qty,posrate=None,amount=None,price=None,msg="",ssid="",obj=None,code=None):
        print("pos creditsell",timekey,qty,posrate,amount,price,msg,ssid,obj,code)
        order={"obj":obj,"bs":"sell","openclose":"credit","price":price,"qty":qty,"pricetype":"limit","ssid":ssid,"msg":msg,"code":code}
        r=self.submit_order(order)
        if r==0:
            print("creditsell失败")
            return -1
        else:
            print("creditsell成功,订单编号",r)
            return r
    def closesell(self,timekey,qty,posrate=None,amount=None,price=None,msg="",ssid="",obj=None,code=None):
        print("pos closesell", timekey, qty, posrate, amount, price, msg, ssid, obj,code)
        order = {"obj": obj, "bs": "sell", "openclose": "close", "price": price, "qty": qty, "pricetype": "limit","code":code,
                 "ssid": ssid, "msg": msg}
        r = self.submit_order(order)
        if r==0:
            print("closesell失败")
            return -1
        else:
            print("closesell成功,订单编号",r)
            return r
    def opensell(self,timekey,qty,posrate=None,amount=None,price=None,msg="",ssid="",obj=None,code=None):
        print("pos opensell",timekey,qty,posrate,amount,price,msg,ssid,obj,code)
        order={"obj":obj,"bs":"sell","openclose":"open","price":price,"qty":qty,"pricetype":"limit","ssid":ssid,"msg":msg,"code":code}
        r=self.submit_order(order)
        if r==0:
            print("opensell失败")
            return -1
        else:
            print("opensell成功,订单编号",r)
            return r
    def closebuy(self,timekey,qty,posrate=None,amount=None,price=None,msg="",ssid="",obj=None,code=None):
        print("pos closebuy", timekey, qty, posrate, amount, price, msg, ssid, obj,code)
        order = {"obj": obj, "bs": "buy", "openclose": "close", "price": price, "qty": qty, "pricetype": "limit","code":code,
                 "ssid": ssid, "msg": msg}
        r = self.submit_order(order)
        if r==0:
            print("closebuy失败")
            return -1
        else:
            print("closebuy成功,订单编号",r)
            return r

    def buy(self,timekey,qty,posrate=None,amount=None,price=None,msg="",ssid="",obj=None,code=None):
        return self.openbuy(timekey=timekey,qty=qty,posrate=posrate,amount=amount,price=price,msg=msg,ssid=ssid,obj=obj,code=code)
    def sell(self,timekey,qty,posrate=None,amount=None,price=None,msg="",ssid="",obj=None,code=None):
        return self.closesell(timekey=timekey,qty=qty,posrate=posrate,amount=amount,price=price,msg=msg,ssid=ssid,obj=obj,code=code)
    def on_order(self,r):
        order = self.deal_order(r)
        print("on_order", order)
        if order["qty0"] > 0:
            self.working_orders[order["orderid"]] = order
        isadd = True
        for i in self.orders:
            if i["orderid"] == order["orderid"]:
                i.update(order)
                isadd = False
                break
        if isadd:
            self.orders.append(order)

if  __name__=="__main__":
    import sys
    from jili.core.config import load_config_json

    c = load_config_json(r"E:\qjs\zjhhzc\stoppl\ss\multifactor\pos_calc_live\config.json")
    print("config.json:", c)
    t0=tradetool(c)